package com.jasperframework.boot.common.utils;

import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

/**
  * <p> Date与 java 8 LocalDateTime LocalDate 之间的互相转化 工具方法 </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */
public class DateUtils {

    public static final String PATTERN_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String PATTERN_MMDD = "MMdd";
    public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
    public static final String PATTERN_YYYYMMDD_2 = "yyyy-MM-dd HH:mm:ss";


    /**
     * localDateTime转换秒数
     * @param localDateTime
     * @return
     */
    public static Long localDateTime2Seconds(LocalDateTime localDateTime){
        if(localDateTime == null){
            return 0L;
        }
        return localDateTime.toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * localDateTime转换毫秒数
     * @param localDateTime
     * @return
     */
    public static Long localDateTime2MilliSeconds(LocalDateTime localDateTime){
        if(localDateTime == null){
            return 0L;
        }
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * <p>java.util.Date --> java.time.LocalDateTime</p>
     *
     * @param date 需要转换的 时间
     * @return java.time.LocalDateTime
     * @author daizhao  2018/8/1 10:03
     */
    public static LocalDateTime date2LocalDataTime(Date date) {
        if (date != null) {
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            return LocalDateTime.ofInstant(instant, zone);
        } else {
            return null;
        }
    }

    /**
     * <p>java.time.LocalDateTime --> java.util.Date</p>
     *
     * @param localDateTime 需要转换的 时间
     * @return java.util.Date
     * @author daizhao  2018/8/1 10:02
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        if (localDateTime != null) {
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            return Date.from(instant);
        } else {
            return null;
        }
    }

    /**
     * <p> 比较两个LocalTime的大小,大于等于返回true</p>
     *
     * @param bigTime   大时间
     * @param smallTime 小时间
     * @return boolean
     * @author youq  2018/3/9 20:02
     */
    public static boolean compareTime(LocalTime bigTime, LocalTime smallTime) {
        int compare = bigTime.compareTo(smallTime);
        return compare >= 0;
    }

    /**
     * <p>java.util.Date --> java.time.LocalDate</p>
     *
     * @author daizhao  2018/1/16 10:04
     */
    public static LocalDate date2LocalDate(Date date) {
        if (date != null) {
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
            return localDateTime.toLocalDate();
        } else {
            return null;
        }
    }

    /**
     * <p> java.time.LocalDate --> java.util.Date</p>
     *
     * @author daizhao  2018/1/16 10:08
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (localDate != null) {
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
            return Date.from(instant);
        } else {
            return null;
        }
    }

    /**
     * <p>java.time.LocalTime --> java.util.Date</p>
     *
     * @author daizhao  2018/1/16 10:10
     */
    public static Date localDateTimeAndLocalTime2date(LocalDate localDate, LocalTime localTime) {
        if (localDate != null && localTime != null) {
            LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            return Date.from(instant);
        } else {
            return null;
        }
    }

    /**
     * <p> LocalDateTime转换成时间戳（毫秒）</p>
     *
     * @author youq  2018/3/15 10:17
     */
    public static long localDateTimeToMillisecond(LocalDateTime localDateTime) {
        if (localDateTime != null) {
            return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        } else {
            return 0;
        }
    }

    /**
     * <p>long 秒值 --> LocalDateTime</p>
     *
     * @author daizhao  2018/1/16 10:10
     */
    public static LocalDateTime second2LocalDateTime(Long seconds) {
        if (seconds > 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), ZoneOffset.of("+8"));
        } else {
            return null;
        }
    }

    /**
     * <p>long 毫秒 --> LocalDateTime</p>
     *
     * @author daizhao  2018/1/16 10:10
     */
    public static LocalDateTime millisecond2LocalDateTime(Long millisecond) {
        if (millisecond > 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(millisecond), ZoneOffset.of("+8"));
        } else {
            return null;
        }
    }

    /**
     * <p>LocalDateTime --> long 秒值 </p>
     *
     * @author daizhao  2018/1/16 10:10
     */
    public static long localDateTime2Second(LocalDateTime time) {
        if (time != null) {
            return time.toEpochSecond(ZoneOffset.of("+8"));
        } else {
            return 0;
        }
    }

    /**
     * <p>localDateTime 2 String </p>
     *
     * @param time    需要转化的时间
     * @param pattern 转化的 格式
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localDateTimeFormat(LocalDateTime time, String pattern) {
        if (Objects.nonNull(time)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
            return df.format(time);
        } else {
            return "";
        }
    }

    /**
     * <p>localDate  2 String </p>
     *
     * @param date    需要转化的日期
     * @param pattern 转化的 格式
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localDateTimeFormat(LocalDate date, String pattern) {
        if (Objects.nonNull(date)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
            return df.format(date);
        } else {
            return "";
        }
    }

    /**
     * <p>localTime 2 String </p>
     *
     * @param time    需要转化的时间
     * @param pattern 转化的 格式
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localTimeFormat(LocalTime time, String pattern) {
        if (Objects.nonNull(time)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
            return df.format(time);
        } else {
            return "";
        }
    }

    /**
     * <p>localDateTime 2 yyyy-MM-dd HH:mm:ss String </p>
     *
     * @param time 需要转化的时间
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localDateTimeDefaultFormat(LocalDateTime time) {
        if (Objects.nonNull(time)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            return df.format(time);
        } else {
            return "";
        }
    }

    /**
     * <p>localDate 2 yyyy-MM-dd  String </p>
     *
     * @param date 需要转化的日期
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localDateDefaultFormat(LocalDate date) {
        if (Objects.nonNull(date)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return df.format(date);
        } else {
            return "";
        }
    }

    /**
     * <p>localDate 2  HH:mm:ss String </p>
     *
     * @param time 需要转化的时间
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static String localTimeDefaultFormat(LocalTime time) {
        if (Objects.nonNull(time)) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss");
            return df.format(time);
        } else {
            return "";
        }
    }

    /**
     * <p>yyyy-MM-dd HH:mm:ss String to LocalDateTime</p>
     *
     * @param dateTimeStr 需要转化的时间
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static LocalDateTime string2LocalDateTime(String dateTimeStr) {
        try {
            if (Objects.nonNull(dateTimeStr)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                return LocalDateTime.parse(dateTimeStr, df);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * <p>yyyy-MM-dd HH:mm:ss String to LocalDateTime</p>
     *
     * @param dateTimeStr 需要转化的时间
     * @return java.lang.String
     * @author daizhao  2018/7/4 16:00
     */
    public static LocalDateTime string2LocalDateTime(String dateTimeStr, String pattern) {
        try {
            if (Objects.nonNull(dateTimeStr)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
                return LocalDateTime.parse(dateTimeStr, df);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public static LocalTime string2LocalTime(String dateTimeStr, String pattern) {
        try {
            if (Objects.nonNull(dateTimeStr)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
                return LocalTime.parse(dateTimeStr, df);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public static LocalDate string2LocalDate(String dateDateStr) {
        try {
            if (Objects.nonNull(dateDateStr)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                return LocalDate.parse(dateDateStr, df);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public static LocalTime second2LocalTime(Long seconds) {
        return LocalTime.ofSecondOfDay(seconds);
    }

    /**
     * 获得上月第一天 周日 00:00:00
     */
    public static LocalDate getLastMonthStartDay() {
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 获取上个月的第一天
        return today.minusMonths(1).withDayOfMonth(1);
    }

    /**
     * 获取时间差
     * @param end
     * @param start
     * @return  long  返回秒值
     */
    public static long getSecondsTime(LocalDateTime end, LocalDateTime start) {
        return Duration.between(start, end).getSeconds();
    }

    /**
     * <p>将 localTime 转成对应的 毫秒值</p>
     *
     * @param localTime 需要转换到 localTime
     * @return long 对应 的毫秒值
     * @author daizhao  2019-08-03 16:57
     */
    public static long localTime2MillLong(LocalTime localTime) {
        if (Objects.nonNull(localTime)) {
            int hour = localTime.getHour();
            int minute = localTime.getMinute();
            int second = localTime.getSecond();
            return (hour * 60 * 60 * 1000) + (minute * 60 * 1000) + (second * 1000);
        } else {
            return 0L;
        }
    }

    /**
     * <p>将 毫秒值 转成对应的 LocalTime</p>
     *
     * @param millSecond 需要转换到 毫秒值
     * @return LocalTime 对应 localTime
     * @author daizhao  2019-08-03 16:57
     */
    public static LocalTime millLong2LocalTime(long millSecond) {
        long hour = millSecond / (60 * 60 * 1000);
        long minute = (millSecond - (hour * 60 * 60 * 1000)) / (60 * 1000);
        long second = (millSecond - (hour * 60 * 60 * 1000) - minute * (60 * 1000)) / 1000;
        return LocalTime.of((int) hour, (int) minute, (int) second);

    }

    /**
     * <p>LocalDate转毫秒值</p>
     *
     * @param localDate 时间
     * @return long 毫秒值
     * @author daizhao  2019/8/6 16:17
     */
    public static long localDate2MilliSecond(LocalDate localDate) {
        if (Objects.nonNull(localDate)) {
            return localDate.atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
        }
        return 0;
    }

    /**
     * <p>毫秒值转LocalDate</p>
     *
     * @param milliSecond 毫秒值
     * @return java.time.LocalDate
     * @author daizhao  2019/8/6 16:17
     */
    public static LocalDate milliSecond2LocalDate(long milliSecond) {
        if (milliSecond > 0) {
            return Instant.ofEpochMilli(milliSecond).atZone(ZoneOffset.ofHours(8)).toLocalDate();
        }
        return null;
    }

    /**
     * <p>获取2时间相隔天数</p>
     *
     * @param begin 开始时间
     * @param end   结束时间
     * @return long 天数
     * @author daizhao  2019/8/15 14:31
     */
    public static long date2DvalueDate(LocalDate begin, LocalDate end) {
        if (Objects.isNull(begin) || Objects.isNull(end)) {
            return 0;
        }
        return ChronoUnit.DAYS.between(begin, end) < 0 ? 0 : ChronoUnit.DAYS.between(begin, end);

    }

    /**
     * <p>格式化时间.秒值-->日期</p>
     *
     * @param callDuration 秒值
     * @return java.lang.String
     * @author daizhao  2019/11/1 15:26
     */
    public static String millisecond2Duration(Long callDuration) {
        if (Objects.isNull(callDuration) || 0 == callDuration) {
            return "00:00:00";
        }
        if (1000 > callDuration && 0 < callDuration) {
            return "00:00:01";
        }
        //将秒格式化成HH:mm:ss
        //这里应该用Duration更合理，但它不能格式化成字符串
        //而使用LocalTime，在时间超过24小时后格式化也会有问题（！）
        long hours = callDuration / 1000 / 3600;

        long rem = callDuration / 1000 % 3600;
        long minutes = rem / 60;
        long seconds = rem % 60;

        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    /**
     * <p>计算两个时间的差，小时、分、秒格式化字符串</p>
     *
     */
    public static String computeDurationToHHMMSS(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        LocalTime localTime = millLong2LocalTime(duration.toMillis());
        return String.format("%02d:%02d:%02d", localTime.getHour(), localTime.getMinute(), localTime.getSecond());
    }


    /**
     * 获取当前时间的字符串表示形式，基于指定的时区和格式。
     * @param zone 指定的时区
     * @param pattern 指定的时间格式
     * @param locale 指定的语言环境
     * @return 格式化后的时间字符串
     */
    private static String getCurrentTimeStr(ZoneId zone, String pattern, Locale locale) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, locale);
        return ZonedDateTime.now(zone).format(formatter);
    }

    /**
     * 获取当前GMT（格林威治标准时间）时间的字符串表示形式。
     * GMT时间格式：EEE, d-MMM-yyyy HH:mm:ss z  eg: Thu, 22 Sep 2022 09:41:01 GMT
     * @return 当前GMT时间的字符串
     */
    public static String getCurrentGMTTime() {
        return getCurrentTimeStr(ZoneId.of("GMT"), "EEE, d-MMM-yyyy HH:mm:ss z", Locale.CHINA);
    }

    /**
     * 获取当前GMT（格林威治标准时间）时间的字符串按照指定国家语言的表示形式。
     * @param locale 转换的语言 如：Locale.US、Locale.DE、Locale.CHINA 等  具体查看 java.util.Locale类
     * @return 当前GMT时间的字符串
     */
    public static String getCurrentGMTTime(Locale locale) {
        return getCurrentTimeStr(ZoneId.of("GMT"), "EEE, d-MMM-yyyy HH:mm:ss z", locale);
    }

    /**
     * 获取当前UTC标准格式的时间。
     * UTC时间格式：yyyyMMdd'T'HHmmss'Z' eg: 20210720T112731Z
     * @return 当前UTC时间的字符串
     */
    public static String getCurrentUTCTime() {
        // 使用Instant获取当前的UTC时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'").withZone(ZoneId.of("UTC+8"));
        return Instant.now().atZone(ZoneId.of("UTC+8")).format(formatter);
    }

    /**
     * 将GMT时间格式转换为普通的时间字符串。
     * @param gmtTimeStr GMT时间格式字符串
     * @param locale 转换的语言 如：Locale.US、Locale.DE、Locale.CHINA 等  具体查看 java.util.Locale类
     * @param pattern 时间格式 eg: yyyy-MM-dd HH:mm:ss
     * @return 转换后的时间字符串
     */
    public static String gmtStrToDateStr(String gmtTimeStr, Locale locale, String pattern) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'", locale != null ? locale : Locale.US);
            LocalDateTime parsedTime = LocalDateTime.parse(gmtTimeStr, formatter);
            return parsedTime.format(DateTimeFormatter.ofPattern(pattern));
        } catch (Exception e) {
            System.err.println("Error parsing GMT time string: " + e.getMessage());
            return null; // 或者返回一个错误信息
        }
    }

    /**
     * 获取当前CST时间。
     * CST（中央标准时间，Central Standard Time），代表UTC-6时区，主要适用于美国、加拿大、墨西哥等地区。
     * @return 当前CST时间的字符串
     */
    public static String getCurrentCSTTime() {
        return getCurrentTimeStr(ZoneId.of("America/Chicago"), "EEE MMM dd HH:mm:ss 'CST' yyyy", Locale.US);
    }

    public static void main(String[] args) throws ParseException {
        System.out.println("Current GMT Time: " + getCurrentGMTTime(Locale.CANADA));
        System.out.println("Current UTC Time: " + getCurrentUTCTime());
        System.out.println("Current CST Time: " + getCurrentCSTTime());



    }
}
